从spring HttpStatusCode源码聊聊jdk17新增的sealed关键字
背景
最近在开发的时候看到spring中的HttpStatusCode出现了一个以前低版本jdk没用到的关键字sealed
所以打算来学习研究下这个新语法
何时引进
sealed关键字在jdk15和jdk16都是作为预览特性出现
直到jdk17才被正式引入
作用
sealed关键字主要是用于通过permits关键字明确指定允许继承的子类列表
我们先看看在没有sealed关键字我们是如何限制类的继承
final关键字
如果一个类加上final关键字,则完全禁止类被继承
public final class XiaoZou {}
现在类的访问权限
比如我们不将类设置为public,使用默认的私有权限
package com.xiaozou;
class Animal {}
这样仅同包才能继承Animal
package com.xiaozou;
public class Dog extends Animal {}
缺点
我们可以看到通过上面的几种方式都没有办法只管切灵活的限制类的子类的实现。
比如我想要某个类,仅只能我自定义的几个类去实现。
我的这几个继承类可能是夸包,用上面的方式都不灵活。
那我们看看如何使用sealed关键字进行实现
sealed关键字使用
继承限制
比如我这里有一个父类Car 我想要仅MiniCar和BigCar能继承
那么如何实现这个需求呢?
使用sealed + permits关键字就很简单了
public sealed class Car permits MiniCar, BigCar { }
public final class MiniCar extends Car { }
public final class BigCar extends Car { }
sealed关键字使用说明
-
如果使用
permits限制了MiniCar和BigCar类的继承。则MiniCar和BigCar必须继承Car,否则编译报错 -
MiniCar和BigCar必须声明为final否则也会编译报错
实现的限制
不仅仅是对类的继承进行限制,也可以对接口的实现进行限制。
这里我们就不自己延时了,直接看spring中HttpStatusCode源码中的应用
spring中HttpStatusCode permits的应用
public sealed interface HttpStatusCode extends Serializable permits DefaultHttpStatusCode, HttpStatus {}
可以看到HttpStatusCode接口限制了其实现类只能是DefaultHttpStatusCode和HttpStatus
final class DefaultHttpStatusCode implements HttpStatusCode, Comparable<HttpStatusCode>, Serializable {}
public enum HttpStatus implements HttpStatusCode {}
DefaultHttpStatusCode和HttpStatus也确实实现了HttpStatusCode接口
同时DefaultHttpStatusCode也强制被声明成了final
HttpStatus因为是枚举所以无需声明成final
如果我们自定义一个类去实现HttpStatusCode接口就会发现编译报错

总结
jdk17引入sealed关键字主要有如下几个优势
-
精确控制继承(实现)关系: 通过
permits明确列出允许继承(实现)的子类,避免意外的类扩展 -
增强代码可维护性: 明确的子类(实现)列表使代码结构更清晰,便于后续扩展或重构
-
模式匹配处理更安全
像上面Car的例子我们可以直接使用模式匹配,安全处理所有可能的子类
public static void processCar(Car car) {
switch (car) {
case BigCar bigCar -> System.out.println("BigCar");
case MiniCar miniCar -> System.out.println("MiniCar");
case null -> System.out.println("Null car");
default -> System.out.println("Unknown car type");
}
}